<?php

namespace App\Services;

use GuzzleHttp\Client;

/**
 * 娃娃机硬件系统服务
 *
 * Class Doll
 * @package App\Services
 */
class Doll
{
    protected $platform;

    protected $secret;

    protected $url;

    public function __construct()
    {
        $config = config('services.doll');

        $this->platform = $config['platform'];
        $this->secret = $config['secret'];

        $this->url = $this->getDomain($config['env']) . '/api/index.php';
    }

    /**
     * 娃娃机列表
     *
     * @param int $page
     * @param int $perPage
     * @return array
     *
     * @throws \Exception
     */
    public function dollList($page = 1, $perPage = 20)
    {
        $result = $this->request([
            'act' => 'doll_list',
            'page' => $page,
            'per_page' => $perPage,
        ]);

        return $result['retval'];
    }
    
    /**
     * 设置抓中概率
     *
     * @param string $deviceId
     * @param int $probability 抓中概率，表示大概多少次抓中一次，范围 1~888
     * @return bool
     *
     * @throws \Exception
     */
    public function setWinningProbability($deviceId, $probability)
    {
        if ($probability < 1 || $probability > 888) {
            return false;
        }
        
        $this->request([
            'act' => 'set_winning_probability',
            'device_id' => $deviceId,
            'winning_probability' => $probability,
        ]);
        
        return true;
    }

    /**
     * 申请分配设备
     *
     * @param string $deviceId
     * @param int $userId
     * @return array
     *
     * @throws \Exception
     */
    public function dollAssign($deviceId, $userId)
    {
        $result = $this->request([
            'act' => 'assign',
            'device_id' => $deviceId,
            'user_id' => $userId,
        ]);

        return $result['retval'];
    }

    /**
     * 娃娃机操控
     *
     * @param  string $deviceId
     * @param  int $userId
     * @param  int $action
     * @return array
     *
     * @throws \Exception
     */
    public function dollOperate($deviceId, $userId, $action)
    {
        return $this->request([
            'act' => 'operate',
            'device_id' => $deviceId,
            'action' => $action,
            'user_id' => $userId,
        ]);
    }
    
    /**
     * 查询操作结果
     *
     * @param int $logId 操作记录id
     * @return int 操作结果：0表示没回调结果，1表示成功，2表示失败
     */
    public function dollOperateResult($logId)
    {
        try {
            $result = $this->request([
                'act' => 'operate_result',
                'log_id' => $logId,
            ]);
            
            return intval($result['retval']['operate_result']);
        } catch (\Exception $e) {
            return 0;
        }
    }

    /**
     * 设置游戏时间
     *
     * @param string $deviceId
     * @param int $playtime 秒数，范围 5~60
     * @return array
     *
     * @throws \Exception
     */
    public function setPlaytime($deviceId, $playtime)
    {
        return $this->request([
            'act' => 'set_playtime',
            'device_id' => $deviceId,
            'playtime' => $playtime,
        ]);
    }
    
    /**
     * 获取设备信息
     *
     * @param array|string $deviceIds
     * @return array
     *
     * @throws \Exception
     */
    public function getDeviceSetting($deviceIds)
    {
        $result = $this->request([
            'act' => 'get_device_setting',
            'device_ids' => implode(',', (array) $deviceIds),
        ]);
        
        return $result['retval'];
    }

    /**
     * 获取设备状态信息
     *
     * @param string $deviceId
     * @return array
     *
     * @throws \Exception
     */
    public function getDeviceStatus($deviceId)
    {
        $result = $this->request([
            'act' => 'get_device_status',
            'device_id' => $deviceId,
        ]);

        return $result['retval'];
    }

    /**
     * 创建订单
     *
     * @param  int $userId
     * @param  string $username
     * @param  string $goodsList 商品数组的 json 结构
     * @param  string $address
     * @param  string $mobile
     * @param  string $consignee
     * @return array
     *
     * @throws \Exception
     */
    public function createOrder($userId, $username, $goodsList, $address = '', $mobile = '', $consignee = '')
    {
        $result = $this->request([
            'app' => 'buyer_order',
            'act' => 'create_order',
            'user_id' => $userId,
            'username' => $username,
            'goods_list' => $goodsList,
            'address' => $address,
            'mobile' => $mobile,
            'consignee' => $consignee,
        ], 'POST');
        
        return $result['retval'];
    }

    /**
     * 获取奇艺果的 user token，过期时间为 6 个月
     *
     * @param int $identifier
     * @return string
     *
     * @throws \Exception
     */
    public function getQiyiguoToken($identifier)
    {
        $result = $this->request([
            'app' => 'video',
            'act' => 'create_token',
            'user_id' => $identifier,
        ]);

        return $result['retval']['token'];
    }
    
    /**
     * 获取腾讯云的 user sig，过期时间为 6 个月
     *
     * @param string $identifier
     * @return string
     *
     * @throws \Exception
     */
    public function getQcloudToken($identifier)
    {
        $result = $this->request([
            'act' => 'create_user_sign',
            'identifier' => $identifier,
        ]);
        
        return $result['retval']['sign'];
    }
    
    /**
     * 获取即构的 user token，过期时间为 6 个月
     *
     * @param string $identifier
     * @return string
     *
     * @throws \Exception
     */
    public function getZegoToken($identifier)
    {
        $result = $this->request([
            'app' => 'zego_doll',
            'act' => 'get_token',
            'idname' => $identifier,
        ]);
        
        return $result['retval'];
    }
    
    /**
     * 批量查询娃娃商品信息
     *
     * @param array $ids
     * @return array
     *
     * @throws \Exception
     */
    public function getGoodsInfos($ids)
    {
        $result = $this->request([
            'act' => 'get_goods_infos',
            'goods_ids' => implode(',', $ids),
        ]);
        
        return $result['retval'];
    }

    /**
     * 接口调用方法
     *
     * @param array $params
     * @param string $method
     * @return array
     *
     * @throws \Exception
     */
    protected function request($params, $method = 'GET')
    {
        $client = new Client(['timeout' => 10]);

        $params += [
            'app' => 'doll',
            'ts' => time(),
            'platform' => $this->platform,
        ];

        $params['sign'] = $this->sign($params);

        if ('GET' == $method) {
            $result = $client->get($this->url, ['query' => $params]);
        } else {
            $result = $client->post($this->url, ['form_params' => $params]);
        }

        $result = json_decode($result->getBody()->getContents(), true);
        if (empty($result['done'])) {
            throw new \Exception($result['msg']);
        }

        return $result;
    }

    /**
     * 娃娃机硬件系统域名
     *
     * @param string $env 接口环境
     * @return string
     */
    public function getDomain($env)
    {
        return 'production' == $env ? 'http://doll.artqiyi.com' : 'http://testdoll.artqiyi.com';
    }

    /**
     * 验证服务端回调的令牌
     *
     * @param  string  $sign 需要验证的令牌
     * @param  array  $params 需要验证的参数
     * @return bool
     */
    public function checkSign($sign, array $params)
    {
        return $sign == $this->sign($params);
    }

    /**
     * 签名算法
     *
     * @param  array $params 所有参数
     * @return string
     */
    private function sign($params)
    {
        // app, act, sign 参数不参与签名
        $params = array_except($params, ['app', 'act', 'sign']);

        $string = '';
        ksort($params);
        foreach ($params as $key => $value) {
            $string .= $key . $value;
        }

        return md5(md5($string) . $this->secret);
    }
}
